﻿using System.Collections.Generic;
using TestingConcurrencyBenchmark.Helpers;
using TestingConcurrencyBenchmark.Problems.DiningPhilosophers.Philosophers;

namespace TestingConcurrencyBenchmark.Problems.DiningPhilosophers.DiningPhilosophersSolutions
{
    /// <summary>
    /// An abstract factory that can create a collections of dining philosophers
    /// </summary>
    public abstract class AbstractDiningPhilosophers
    {
        /// <summary>
        /// The number of philosophers this factory should produce
        /// </summary>
        private readonly int _nbPhilosophers;

        protected AbstractDiningPhilosophers(int nbPhilosophers)
        {
            _nbPhilosophers = nbPhilosophers;
        }

        /// <summary>
        /// Creates a collection of Philosopher objects
        /// Each philosopher will have a fork (a semaphore) between it and the next philosopher 
        /// </summary>
        /// <returns>a collection of abstractphilosophers</returns>
        public List<AbstractPhilosopher> CreatePhilosophers()
        {
            List<BenchmarkSemaphore> forks = new List<BenchmarkSemaphore>();
            for (int i = 0; i < _nbPhilosophers; i++)
            {
                forks.Add(new BenchmarkSemaphore(1));
            }
            List<AbstractPhilosopher> philosophers = new List<AbstractPhilosopher>();
            for (int i = 0; i < forks.Count; i++)
            {
                philosophers.Add(CreatePhilosopher(forks[i], forks[(i + 1)%forks.Count]));
            }
            return philosophers;
        }

        /// <summary>
        /// Implementations will need to instantiate a type of philosopher for this factory to work
        /// </summary>
        /// <param name="leftFork">the fork (semaphore) to the left of the philosopher</param>
        /// <param name="rightFork">the fork (semaphore) to the right of the philosopher</param>
        /// <returns>a new philosopher</returns>
        protected abstract AbstractPhilosopher CreatePhilosopher(BenchmarkSemaphore leftFork, BenchmarkSemaphore rightFork);
    }
}